#ifndef _POLL_SVR_H_
#define _POLL_SVR_H_

#include <iostream>
#include <string>

#include <poll.h>

#include "Sock.hpp"

using namespace std;

#define FD_NONE -1

class PollServer
{
public:
    static const int nfds = 100;
public:
    PollServer(const uint16_t& port = 8080)
        : _port(port)
        , _nfds(nfds)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "create base socket success");

        // 申请_nfds个struct pollfd结构体
        _fds = new struct pollfd[_nfds];
        // 初始化_fds
        for (int i = 0; i < _nfds; i++)
        {
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0;
        }
        // 将_listensock设置到_fds，并设置events为POLLIN，关心读事件
        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN;

        _timeout = 1000;
    }
    void Start()
    {
        while (true)
        {
            DebugPrint();
            int n = poll(_fds, _nfds, -1);
            switch(n)
            {
            case 0:
                logMessage(DEBUG, "time out...");
                break;
            case -1:
                logMessage(WARNING, "poll error: %d : %s", errno, strerror(errno));
                break;
            default:
                // 成功，下面就是调用处理函数
                HandlerEvent();
                break;
            }
        }
    }

    ~PollServer()
    {
        if (_listensock >= 0) close(_listensock);
        if (_fds) delete[] _fds;
    }

private:
    void Accepter()
    {
        string clientip;
        uint16_t clientport = 0;

        // _listensock获取了新的连接
        int sock = Sock::Accept(_listensock, &clientip, &clientport);
        if (sock < 0)
        {
            logMessage(WARNING, "accept error");
            return;
        }
        logMessage(DEBUG, "get a new link success: [%s:%d]: %d", clientip.c_str(), clientport, sock);
        int pos = 1;
        while (_fds[pos].fd != FD_NONE) pos++;
        if (pos == _nfds)
        {
            // 说明数组中fd已经满了，这里也可以设置成动态的，可以扩容
            logMessage(WARNING, "%s:%d", "poll server already full, close: %d", sock);
            close(sock);
        }
        else
        {
            _fds[pos].fd = sock;
            _fds[pos].events = POLLIN;
        }
    }

    void Recver(int pos)
    {
        char buffer[1024];
        int n = recv(_fds[pos].fd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _fds[pos].fd, buffer);
        }
        else if (n == 0)
        {
            logMessage(DEBUG, "client[%d]: quit, me too...", _fds[pos].fd);
            // 对端已经关闭，关闭对应文件描述符，把该文件描述符从数组中去掉
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = _fds[pos].revents = 0;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error, %d : %s", _fds[pos].fd, errno, strerror(errno));
            // 读取错误，关闭对应文件描述符，把该文件描述符从数组中去掉
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = _fds[pos].revents = 0;
        }
    }

    void HandlerEvent()
    {
        for (int i = 0; i < _nfds; i++)
        {
            if (_fds[i].fd == FD_NONE) continue; // 去掉不合法的fd
            if (_fds[i].revents & POLLIN) // 判断文件描述符是否就绪
            {
                if (_fds[i].fd == _listensock)
                {
                    // listensock就绪，连接事件到来
                    Accepter();
                }
                else
                {
                    // 其他sock就绪，读事件到来，本次fd上的数据就绪，不会被阻塞
                    Recver(i);
                }
            }
        }
    }
    void DebugPrint()
    {
        cout << "fd_array[]: ";
        for (int i = 0; i < _nfds; i++)
        {
            if (_fds[i].fd == FD_NONE) continue;
            cout << _fds[i].fd << " ";
        }
        cout << endl;
    }
private:
    uint16_t _port;
    int _listensock;
    struct pollfd* _fds;
    int _nfds;
    int _timeout;
};

#endif 